package 异常处理;

public class 使用SLF4J和Logback {

}
/*
前面介绍了Commons Logging和Log4j这一对好基友，它们一个负责充当日志API，一个负责实现日志底层，搭配使用非常便于开发。

有的童鞋可能还听说过SLF4J和Logback。这两个东东看上去也像日志，它们又是啥？

其实SLF4J类似于Commons Logging，也是一个日志接口，而Logback类似于Log4j，是一个日志的实现。

为什么有了Commons Logging和Log4j，又会蹦出来SLF4J和Logback？这是因为Java有着非常悠久的开源历史，不但OpenJDK本身是开源的，而且我们用到的第三方库，几乎全部
都是开源的。开源生态丰富的一个特定就是，同一个功能，可以找到若干种互相竞争的开源库。

因为对Commons Logging的接口不满意，有人就搞了SLF4J。因为对Log4j的性能不满意，有人就搞了Logback。

我们先来看看SLF4J对Commons Logging的接口有何改进。在Commons Logging中，我们要打印日志，有时候得这么写：

int score = 99;
p.setScore(score);
log.info("Set score " + score + " for Person " + p.getName() + " ok.");
拼字符串是一个非常麻烦的事情，所以SLF4J的日志接口改进成这样了：

int score = 99;
p.setScore(score);
logger.info("Set score {} for Person {} ok.", score, p.getName());
我们靠猜也能猜出来，SLF4J的日志接口传入的是一个带占位符的字符串，用后面的变量自动替换占位符，所以看起来更加自然。

如何使用SLF4J？它的接口实际上和Commons Logging几乎一模一样：

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class Main {
    final Logger logger = LoggerFactory.getLogger(getClass());
}
对比一下Commons Logging和SLF4J的接口：

Commons Logging	                            SLF4J
org.apache.commons.logging.Log	             org.slf4j.Logger
org.apache.commons.logging.LogFactory	       org.slf4j.LoggerFactory

不同之处就是Log变成了Logger，LogFactory变成了LoggerFactory。

使用SLF4J和Logback和前面讲到的使用Commons Logging加Log4j是类似的，先分别下载SLF4J和Logback，然后把以下jar包放到classpath下：

•slf4j-api-2.0.7.jar
•logback-classic-1.4.7.jar
•logback-core-1.4.7.jar
•logback-access-1.4.7.jar

然后使用SLF4J的Logger和LoggerFactory即可。和Log4j类似，我们仍然需要一个Logback的配置文件，把logback.xml放到classpath下，配置如下：

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

	<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
		<encoder>
			<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
		</encoder>
	</appender>

	<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
		<encoder>
			<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
			<charset>utf-8</charset>
		</encoder>
		<file>log/output.log</file>
		<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
			<fileNamePattern>log/output.log.%i</fileNamePattern>
		</rollingPolicy>
		<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
			<MaxFileSize>1MB</MaxFileSize>
		</triggeringPolicy>
	</appender>

	<root level="INFO">
		<appender-ref ref="CONSOLE" />
		<appender-ref ref="FILE" />
	</root>
</configuration>
运行即可获得类似如下的输出：

13:15:25.328 [main] INFO  com.itranswarp.learnjava.Main - Start process...
从目前的趋势来看，越来越多的开源项目从Commons Logging加Log4j转向了SLF4J加Logback
*/
/*
slf4j
简介
SLF4J，即简单日志门面(Simple Logging Facade for Java)，不是具体的日志解决方案，它只服务于各种各样的日志系统。在使用SLF4J的时候，不需要在代码中或配置文件中
指定你打算使用那个具体的日志系统。

使用步骤
引入slf4j依赖，这里以maven项目为例
<dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.22</version>
    </dependency>
</dependencies>

代码编写记录日志语句,示例如下
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    //定义日志对象
    private static Logger logger = LoggerFactory.getLogger(Main.class);

    public static void main(String... strings) {
        //级别为debug的日志
        logger.debug("Hello! debug!");
        //级别为info的日志
        logger.info("Hello! info!");
        //级别为warn的日志
        logger.warn("Hello! warn!");
        //级别为error的日志
        logger.error("Hello! error!");
    }
}

以上两步即可记录日志了，不过在运行程序之后会出现如下问题:

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

说明光引入slf4j还不够，必须得挑选一个具体的日志组件实现来完成日志的记录，下面介绍一款不错的日志实现:logback

【logback】
Logback是由log4j创始人设计的一个开源日志组件。logback当前分成三个模块：logback-core,logback-classic和logback-access。logback-core是其它两个
模块的基础模块。logback-classic是log4j的一个改良版本。

我们这里的实例使用到logback-classic

使用步骤
引入slf4j以及logback依赖，这里以maven项目为例
<dependencies>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.22</version>
    </dependency>

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.1.6</version>
    </dependency>

</dependencies>

classpath中编写logback的配置文件logback.xml, 以maven项目为例，logback.xml文件放在/src/main/resources/路径中
logback.xml配置实例及注释详解

<?xml version="1.0" encoding="UTF-8"?>
<!-- scan:当此属性设置为true时，配置文件如果发生改变，将会被重新加载，默认值为true。 
     scanPeriod:设置监测配置文件是否有修改的时间间隔，如果没有给出时间单位，默认单位是毫秒。当scan为true时，此属性生效。默认的时间间隔为1分钟。
     debug:当此属性设置为true时，将打印出logback内部日志信息，实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">

    <!--上下文变量设置,用来定义变量值,其中name的值是变量的名称，value的值时变量定义的值。通过<property>定义的值会被插入到logger上下文中。定义变量后，可以使“${}”来使用变量。 -->
    <property name="CONTEXT_NAME" value="logback-test" />

    <!-- 上下文名称：<contextName>, 每个logger都关联到logger上下文，默认上下文名称为“default”。但可以使用<contextName>设置成其他名字，用于区分不同应用程序的记录。
        一旦设置，不能修改。 -->
    <contextName>${CONTEXT_NAME}</contextName>

    <!-- <appender>是<configuration>的子节点，是负责写日志的组件。有两个必要属性name和class。name指定appender名称，class指定appender的实现类。-->
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 对日志进行格式化。 -->
        <encoder>
            <pattern>
                %d{yyyy-MM-dd HH:mm:ss.SSS}|%level|%class|%thread|%method|%line|%msg%n
            </pattern>
        </encoder>
    </appender>

    <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 被写入的文件名，可以是相对目录，也可以是绝对目录，如果上级目录不存在会自动创建，没有默认值。 -->
        <file>${logs.dir}/logback-test.log</file>

        <!-- 当发生滚动时的行为  -->
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <!-- 必须包含“%i”例如，假设最小值和最大值分别为1和2，命名模式为 mylog%i.log,会产生归档文件mylog1.log和mylog2.log。还可以指定文件压缩选项，例如，mylog%i.log.gz 或者 没有log%i.log.zip -->
            <FileNamePattern>${logs.dir}/logback-test.%i.log</FileNamePattern>
            <!-- 窗口索引最小值 -->
            <minIndex>1</minIndex>
            <!-- 窗口索引最大值 -->
            <maxIndex>1</maxIndex>
        </rollingPolicy>

        <!-- 激活滚动的条件。 -->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <!-- 活动文件的大小，默认值是10MB -->
            <maxFileSize>30MB</maxFileSize>
        </triggeringPolicy>

        <!-- 对记录事件进行格式化。 -->
        <encoder>
            <charset>UTF-8</charset>
            <Pattern>
                %d{yyyy-MM-dd HH:mm:ss.SSS}|%level|%class|%thread|%method|%line|%msg%n
            </Pattern>
        </encoder>
    </appender>

    <!-- 特殊的<logger>元素，是根logger。只有一个level属性，应为已经被命名为"root".
        level:设置打印级别，大小写无关：TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF，不能设置为INHERITED或者同义词NULL。默认是DEBUG。
        <root>可以包含零个或多个<appender-ref>元素，标识这个appender将会添加到这个loger。 -->
    <root>
        <level value="WARN" />
        <appender-ref ref="stdout" />
        <appender-ref ref="file" />
    </root>

    <!-- 用来设置某一个 包 或者具体的某一个 类 的日志打印级别、以及指定<appender>, 
        name:用来指定受此logger约束的某一个包或者具体的某一个类。
        level:用来设置打印级别，大小写无关：TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF，还有一个特俗值INHERITED或者同义词NULL，代表强制执行上级的级别。如果未设置此属性，那么当前loger将会继承上级的级别。 
        additivity:是否向上级logger传递打印信息。默认是true。(这个logger的上级就是上面的root)
        <logger>可以包含零个或多个<appender-ref>元素，标识这个appender将会添加到这个logger。-->
    <logger name="xuyihao.logback.test" level="DEBUG" additivity="true"></logger>

</configuration>

通过以上配置，在程序运行之后，slf4j会加载logback的日志实现，然后logback从类路径中读取logback.xml文件中的日志配置信息，实现日志的记录等功能。
重新运行以上程序，结果如下：

2017-08-24 17:00:22.354|DEBUG|xuyihao.logback.test.Main|main|main|14|Hello! debug!
2017-08-24 17:00:22.354|INFO|xuyihao.logback.test.Main|main|main|15|Hello! info!
2017-08-24 17:00:22.354|WARN|xuyihao.logback.test.Main|main|main|16|Hello! warn!
2017-08-24 17:00:22.354|ERROR|xuyihao.logback.test.Main|main|main|17|Hello! error!

*/
/*


 */
*/